package org.tlang.parser;

import org.tlang.exception.ParseException;
import org.tlang.keywords.KeyWords;
import org.tlang.lexer.Lexer;
import org.tlang.lexer.token.Token;
import org.tlang.ast.AST;
import org.tlang.ast.list.clazz.ClassBody;
import org.tlang.ast.list.clazz.ClassDefine;
import org.tlang.ast.list.clazz.NewClassInvoker;
import org.tlang.ast.list.func.FunctionDefine;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 类解析器
 */
public class ClassParser extends FunctionParser {

    public ClassParser(Lexer lexer) {
        super(lexer);
    }

    /**
     * class_body: "{" { var_define | func_define } "}"
     */
    protected AST classBody() throws ParseException {
        skip("{");
        List<AST> result = new ArrayList<>();
        while (true) {
            if (!isIdentifier("}")) {
                if (isIdentifier(KeyWords.VAR)) {
                    result.add(varDefineStatement());
                } else if (isIdentifier(KeyWords.FUNC)) {
                    result.add(functionDefine());
                } else if (isIdentifier(KeyWords.CONSTRUCTOR)) {
                    result.add(constructorDefine());
                } else {
                    throw new ParseException("bad define in class body", lexer.poll());
                }
                continue;
            }

            skip("}");
            return new ClassBody(result);
        }
    }

    /**
     * class_define: "class" IDENTIFIER [ "extends" IDENTIFIER ] class_body
     */
    protected AST classDefine() throws ParseException {
        skip(KeyWords.CLASS);
        List<AST> result = new ArrayList<>();
        result.add(identifier());

        if (isIdentifier(KeyWords.EXTENDS)) {
            skip(KeyWords.EXTENDS);
            result.add(identifier());
        }

        result.add(classBody());
        return new ClassDefine(result);
    }

    /**
     * 类构造函数，与普通函数定义唯一的差别就是没有func关键词前缀
     * <p>
     * constructor_define : "constructor" parameter_list block
     */
    protected AST constructorDefine() throws ParseException {
        List<AST> result = new ArrayList<>();

        result.add(identifier());
        result.add(parameterList());
        result.add(block());

        return new FunctionDefine(result);
    }

    /**
     * factor: "new" IDENTIFIER argument_list | super_factor
     */
    @Override
    protected AST factor() throws ParseException {
        Token token0 = lexer.peek(0);
        Token token1 = lexer.peek(1);
        Token token2 = lexer.peek(2);

        if (token0.isIdentifier() && token1.isIdentifier() && token2.isIdentifier()
                && KeyWords.NEW.equals(token0.getText()) && "(".equals(token2.getText())) {
            skip(KeyWords.NEW);
            return new NewClassInvoker(Arrays.asList(identifier(), argumentList()));
        }
        return super.factor();
    }
}
